package com.irdstudio.efp.flow.api.rest;

import com.irdstudio.basic.framework.core.constant.ApplicationConstance;
import com.irdstudio.basic.framework.core.constant.BaseConstant;
import com.irdstudio.basic.framework.core.constant.ResponseData;
import com.irdstudio.basic.framework.core.util.StringUtil;
import com.irdstudio.basic.framework.core.util.TimeUtil;
import com.irdstudio.efp.flow.executor.util.AbstractController;
import com.irdstudio.efp.flow.service.FlowCommonService;
import com.irdstudio.efp.flow.service.OutsDistrCaseComnService;
import com.irdstudio.efp.riskm.common.RiskColltConstant;
import com.irdstudio.efp.riskm.service.facade.CaseDistrRatioService;
import com.irdstudio.efp.riskm.service.facade.ColltTaskDistrService;
import com.irdstudio.efp.riskm.service.facade.ColltTaskInfoService;
import com.irdstudio.efp.riskm.service.vo.CaseDistrRatioVO;
import com.irdstudio.efp.riskm.service.vo.ColltTaskDistrVO;
import com.irdstudio.efp.riskm.service.vo.ColltTaskInfoVO;
import com.irdstudio.efp.riskm.service.vo.CooprOrgInfoVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@RestController
@RequestMapping("/api")
public class ColltTaskDistrController extends AbstractController {

    @Autowired
    @Qualifier("colltTaskDistrService")
    private ColltTaskDistrService colltTaskDistrService;

    @Autowired
    @Qualifier("colltTaskInfoService")
    private ColltTaskInfoService colltTaskInfoService;

    @Autowired
    @Qualifier("caseDistrRatioService")
    private CaseDistrRatioService caseDistrRatioService;

    @Autowired
    private FlowCommonService flowCommonService;

    @Autowired
    private OutsDistrCaseComnService outsDistrCaseComnService;

    @Value("${DIVISIONLMT}")
    private BigDecimal divisionLmt;

    /**
     * 日志信息
     */
    private final Logger logger = LoggerFactory.getLogger(ColltTaskDistrController.class);

    /**
     * 分案机构版本号展示
     *
     * @return
     * @author wanglihua
     * @params * @param null
     * @date 2019/11/27 20:06
     * @version 0.1
     * @since 2019/11/27 20:06
     */
    @RequestMapping(value = "/distri/rate/orgver", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<CaseDistrRatioVO>> searchVersionNo(@RequestBody ColltTaskDistrVO vo) {
        List<CaseDistrRatioVO> outputVo = new ArrayList<>();
        try {
            if (!StringUtil.isNullorBank(vo.getVersionNo())) {
                logger.info("查询条件的分案机构分案比例版本号：" + vo.getVersionNo());
                outputVo = queryOrgInfosByVno(vo.getCooprOrgType(), vo.getVersionNo());
            } else {
                //获取合作状态为"正常"的合作机构
                List<CooprOrgInfoVO> cooprOrgInfos = flowCommonService.getDistrCooprOrgInfos(vo.getCooprOrgType());
                logger.info("合作状态为正常的合作机构" + cooprOrgInfos.toString());
                //获取合作机构编号集
                List<String> cooprOrgNos = cooprOrgInfos.stream().map(CooprOrgInfoVO::getCooprOrgNo).collect(Collectors.toList());
                //获取分案机构分案比例版本号
                outputVo = queryOrgInfos(vo.getCooprOrgType(), cooprOrgNos);
            }
            logger.info("有效的分案机构分案比例版本号：" + outputVo.toString());
        } catch (Exception e) {
            logger.error(e.getMessage());
            return ResponseData.create(null, ApplicationConstance.FAILURE, e.getMessage(), false);
        }
        return getResponseData(outputVo);
    }

    private List<CaseDistrRatioVO> queryOrgInfosByVno(String cooprOrgType, String versionNo) throws Exception {
        logger.info("获取合作状态为“正常”的合作机构的查询参数为：合作机构类型代码:" + cooprOrgType + ",版本号:" + versionNo);
        CaseDistrRatioVO queryCondition = new CaseDistrRatioVO();
        if (RiskColltConstant.COOPR_ORG_TYPE_002.equals(cooprOrgType)) {
            queryCondition.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_002);
        }
        if (RiskColltConstant.COOPR_ORG_TYPE_003.equals(cooprOrgType)) {
            queryCondition.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_003);
        }
        queryCondition.setVersionNo(versionNo);
        List<CaseDistrRatioVO> orgList = caseDistrRatioService.getUsefulOrgsCaseInfos(queryCondition);
        if (Objects.isNull(orgList)) throw new Exception("查询到的合作机构为空，无法分案！");
        return orgList;
    }

    private List<CaseDistrRatioVO> queryOrgInfos(String cooprOrgType, List<String> cooprOrgNos) throws Exception {
        logger.info("获取合作状态为“正常”的合作机构的查询参数为：合作机构类型代码:" + cooprOrgType + ",有效机构号:" + cooprOrgNos.toString());
        CaseDistrRatioVO queryCondition = new CaseDistrRatioVO();
        if (RiskColltConstant.COOPR_ORG_TYPE_002.equals(cooprOrgType)) {
            queryCondition.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_002);
        }
        if (RiskColltConstant.COOPR_ORG_TYPE_003.equals(cooprOrgType)) {
            queryCondition.setCooprOrgType(RiskColltConstant.COOPR_ORG_TYPE_003);
        }
        queryCondition.setCooprOrgNos(cooprOrgNos);
        List<CaseDistrRatioVO> orgList = caseDistrRatioService.getUsefulOrgsCaseInfos(queryCondition);
        if (Objects.isNull(orgList)) throw new Exception("查询到的合作机构为空，无法分案！");
        return orgList;
    }

    /**
     * 分案机构比例详情展示
     *
     * @return
     * @author wanglihua
     * @params * @param null
     * @date 2019/11/29 16:46
     * @version 0.1
     * @since 2019/11/29 16:46
     */
    @RequestMapping(value = "/distri/rate/orgver/detail", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<CaseDistrRatioVO>> getVersionNo(@RequestBody CaseDistrRatioVO caseDistrRatioVO) {
        List<CaseDistrRatioVO> outputVo = caseDistrRatioService.getOrgListByPage(caseDistrRatioVO);
        logger.info("经确认查询得到的分案机构信息：" + outputVo.toString());
        return getResponseData(outputVo);
    }

    /**
     * 催收分案
     *
     * @return
     * @author wanglihua
     * @params * @param null
     * @date 2019/9/9 9:18
     * @version 0.1
     * @since 2019/9/9 9:18
     */
    @RequestMapping(value = "/collt/task/infos/div", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<Integer> districuteCase(@RequestBody ColltTaskDistrVO vo) {
        setUserInfoToVO(vo);
        int outputVo = 1;
        ResponseData<Integer> result = new ResponseData<>();
        //获取任务
        try {
            //获取案件信息
            List<ColltTaskInfoVO> caseList = queryCasesInfos(vo);
/*			//获取合作状态为"正常"的合作机构
			List<CooprOrgInfoVO> cooprOrgInfos = flowCommonService.getDistrCooprOrgInfos(vo.getCooprOrgType());
			//获取合作机构编号集
			List<String> cooprOrgNos = cooprOrgInfos.stream().map(CooprOrgInfoVO::getCooprOrgNo).collect(Collectors.toList());*/
            //获取合作机构信息
//			List<CaseDistrRatioVO> orgList = queryOrgInfos(vo, cooprOrgNos);
            List<CaseDistrRatioVO> orgList = caseDistrRatioService.getOrgList(vo.getVersionNo());
            //检查信息案件信息
            caseList = checkCasesInfo(caseList);
            //检查机构信息
            orgList = checkOrgsInfo(orgList);
            //批次号
            String colltBatchNo = outsDistrCaseComnService.getBatchNo();
            //分案申请流水号
            String distrCaseApply = outsDistrCaseComnService.getDistrCaseApply();
            //发起分案申请流程
            outsDistrCaseComnService.submitDistrCaseAppr(distrCaseApply, colltBatchNo, vo.getColltWay(), vo);
            //分配
            Map<ColltTaskDistrVO, List<ColltTaskInfoVO>> enableDataMap = divCases(caseList, orgList, colltBatchNo);
            //插入催收任务分配、更新任务表信息
            saveAndUpdate(enableDataMap, vo);
        } catch (Exception e) {
            outputVo = -1;
            result.setSuccess(false);
            result.setMessage(e.getMessage());
            result.setCode(ApplicationConstance.FAILURE);
            e.printStackTrace();
            return result;
        }
        return getResponseData(outputVo);
    }

    private void saveAndUpdate(Map<ColltTaskDistrVO, List<ColltTaskInfoVO>> enableDataMap, ColltTaskDistrVO vo) throws Exception {
        Iterator<ColltTaskDistrVO> iterator = enableDataMap.keySet().iterator();
        List<ColltTaskDistrVO> taskDistrs = new ArrayList<>();
        while (iterator.hasNext()) {
            //催收任务分配信息
            ColltTaskDistrVO colltTaskDistr = iterator.next();
            colltTaskDistr.setColltWay(vo.getColltWay());
            colltTaskDistr.setIsPassDistr(BaseConstant.NO_N);
            colltTaskDistr.setOpUserCode(vo.getOpUserCode());
            colltTaskDistr.setOpOrgCode(vo.getOpOrgCode());
            colltTaskDistr.setCreateUser(vo.getOpUserCode());
            taskDistrs.add(colltTaskDistr);
            //任务信息
            List<ColltTaskInfoVO> colltTaskInfoList = enableDataMap.get(colltTaskDistr);
            colltTaskInfoList.forEach(item -> {
                item.setOutsOrgCode(colltTaskDistr.getOutsOrgCode());
                item.setOutsOrgName(colltTaskDistr.getOutsOrgName());
                item.setColltBatchNo(colltTaskDistr.getColltBatchNo());
                item.setIsTaskDistr(BaseConstant.YES_Y);
                item.setIdentWay(RiskColltConstant.IDENT_WAY_02);
                item.setOpUserCode(colltTaskDistr.getOpUserCode());
                item.setOpOrgCode(colltTaskDistr.getOpOrgCode());
                item.setLastUpdateUser(vo.getLoginUserId());
            });
            logger.info("机构" + colltTaskDistr.getOutsOrgName() + "(" + colltTaskDistr.getOutsOrgCode() + ")分配到的案件信息为：" + colltTaskInfoList.toString());
            int num = 0;
            if (Objects.nonNull(colltTaskInfoList) && !colltTaskInfoList.isEmpty()) {
                num = colltTaskInfoService.batchUpdateVO(colltTaskInfoList);
            } else {
                logger.info("任务信息为空！");
            }
            if (num < 0) throw new Exception("批量更新任务信息表失败！");
        }
        //计算分配金额占比之和，不等于1则做处理
        BigDecimal proportionTotal = new BigDecimal("0");
        BigDecimal temp = new BigDecimal("0");
        proportionTotal = taskDistrs.stream().map(ColltTaskDistrVO::getDistrLmtRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (BigDecimal.ONE.compareTo(proportionTotal) == -1) {
            temp = taskDistrs.get(0).getDistrLmtRatio().subtract(proportionTotal.subtract(BigDecimal.ONE));
        } else {
            temp = taskDistrs.get(0).getDistrLmtRatio().add(BigDecimal.ONE.subtract(proportionTotal));
        }
        taskDistrs.get(0).setDistrLmtRatio(temp);
        //插入
        int num = colltTaskDistrService.batchInsert(taskDistrs);
        if (num < 0) throw new Exception("批量插入催收任务分配表失败！");
    }

    private Map<ColltTaskDistrVO, List<ColltTaskInfoVO>> divCases(List<ColltTaskInfoVO> caseList, List<CaseDistrRatioVO> orgList, String batchNo) throws Exception {
        logger.info("用于分案的机构信息：" + orgList.toString());
        //根据逾期金额由大到小顺序排列案件
        caseList.sort((x, y) -> y.getOverLmt().compareTo(x.getOverLmt()));
        //根据案件分配占比由大到小顺序排列
        orgList.sort((x, y) -> y.getCaseRatio().compareTo(x.getCaseRatio()));
        //分离出由大到小排序的大于金额5w的案件
        List<ColltTaskInfoVO> largeLmtCasesList = caseList.stream().filter(a -> divisionLmt.compareTo(a.getOverLmt()) == -1 || divisionLmt.compareTo(a.getOverLmt()) == 0).collect(Collectors.toList());
        //分离出由大到小排序的小于金额5w的案件
        List<ColltTaskInfoVO> smallLmtCasesList = caseList.stream().filter(a -> divisionLmt.compareTo(a.getOverLmt()) > -1 && divisionLmt.compareTo(a.getOverLmt()) != 0).collect(Collectors.toList());
        //案件总量
        BigDecimal casesTotal = new BigDecimal(caseList.size());
        //大额案件总量
        int largeLmtCasesTotal = largeLmtCasesList.size();
        //小额案件总量
        int smallLmtCasesTotal = smallLmtCasesList.size();
        //机构总数
        BigDecimal orgTotal = new BigDecimal(orgList.size());
        //案件总金额
        BigDecimal lmtTotal = new BigDecimal(0);
        lmtTotal = caseList.stream().map(ColltTaskInfoVO::getOverLmt).reduce(BigDecimal.ZERO, BigDecimal::add);
        logger.info("分案相应所需信息：案件总量：" + casesTotal + "，大额案件数：" + largeLmtCasesTotal + "，小额案件数：" + smallLmtCasesTotal + "，机构总数："
                + orgTotal + "，案件总金额：" + lmtTotal);
        //处理数据前暂存分配后的信息
        Map<CaseDistrRatioVO, List<ColltTaskInfoVO>> tempMap = new HashMap<>();
        //用于存放处理后的信息
        Map<ColltTaskDistrVO, List<ColltTaskInfoVO>> enableDataMap = new HashMap<>();
        //计算每个机构分得大额案件数量的平均值，若不足整数则从小额案件里补足
        int remainCases = largeLmtCasesTotal % orgTotal.intValue();
        int aveCases = largeLmtCasesTotal / orgTotal.intValue();
        if (remainCases > 0) {
            aveCases += 1;
            for (int i = 1; i <= orgTotal.intValue() - remainCases; i++) {
                if (smallLmtCasesList.size() > 0) {
                    largeLmtCasesList.add(smallLmtCasesList.get(0));
                    smallLmtCasesList.remove(smallLmtCasesList.get(0));
                }
            }
        }
        logger.info("**************************开始对大额案件分组！**************************");
        //对大额案件的案件数进行分组
        List<List<ColltTaskInfoVO>> spiltCaseList = Stream.iterate(0, n -> n + 1)
                .limit(aveCases)
                .parallel()
                .map(a -> largeLmtCasesList.stream()
                        .skip(a * orgTotal.intValue())
                        .limit(orgTotal.intValue())
                        .parallel()
                        .collect(Collectors.toList()))
                .collect(Collectors.toList());
        logger.info("**************************大额案件分组结束！**************************");
        //先分配大额案件
        logger.info("**************************开始大额案件的分案！**************************");
        for (int i = 0; i < orgTotal.intValue(); i++) {
            //接收案件
            List<ColltTaskInfoVO> aveRs = new ArrayList<>();
            logger.info("大额案件分案：机构" + orgList.get(i).getCooprOrgName() + "(" + orgList.get(i).getCooprOrgNo() + ")分配比例为：" + orgList.get(i).getCaseRatio());
            //机构分配的案件数
            BigDecimal divCaseNum = orgList.get(i).getCaseRatio().multiply(casesTotal).setScale(0, BigDecimal.ROUND_HALF_UP);
            for (int m = 0; m < aveCases; m++) {
                if (divCaseNum.intValue() > aveRs.size()) {
                    aveRs.add(spiltCaseList.get(m).get(0));
                    spiltCaseList.get(m).remove(0);
                }
            }
            //存入中间Map
            tempMap.put(orgList.get(i),aveRs);
        }
        logger.info("**************************大额分案结束！**************************");
        //将未分配的大额案件并入小额案件
        for (int m = 0; m < aveCases; m++) {
            smallLmtCasesList.addAll(spiltCaseList.get(m));
        }
        //开始为n-1个机构分配催收任务，剩下的都分给最后一个机构
        logger.info("**************************开始对前N-1个机构进行小额案件的分案！**************************");
        for (int i = 0; i < orgTotal.intValue() - 1; i++) {
            //接收案件
            List<ColltTaskInfoVO> rs = new ArrayList<>();
            logger.info("小额案件分案：机构" + orgList.get(i).getCooprOrgName() + "(" + orgList.get(i).getCooprOrgNo() + ")分配比例为：" + orgList.get(i).getCaseRatio());
            //机构分配的案件数
            BigDecimal divCaseNum = orgList.get(i).getCaseRatio().multiply(casesTotal).setScale(0, BigDecimal.ROUND_HALF_UP);
            for (int j = 0; j < divCaseNum.intValue() - aveCases; j++) {
                if (j % 2 == 0) {
                    //取金额最大的
                    rs.add(smallLmtCasesList.get(smallLmtCasesList.size() - 1));
                    smallLmtCasesList.remove(smallLmtCasesList.size() - 1);
                } else if (j % 2 == 1) {
                    //取最小值
                    rs.add(smallLmtCasesList.get(0));
                    smallLmtCasesList.remove(0);
                }
            }
            //存入中间Map
            //将小额分案结果跟大额分案结果整合起来
            tempMap.get(orgList.get(i)).addAll(rs);
//			tempMap.put(orgList.get(i),rs);
        }
        logger.info("**************************小额分案结束！**************************");
        //给最后一个机构分配任务
        BigDecimal divCaseNum = orgList.get(orgList.size() - 1).getCaseRatio().multiply(casesTotal).setScale(0, BigDecimal.ROUND_HALF_UP);
        for (int i = 0; i < divCaseNum.intValue() - aveCases; i++) {
            if (smallLmtCasesList.size() > 0) {
                tempMap.get(orgList.get(orgList.size() - 1)).add(smallLmtCasesList.get(0));
                smallLmtCasesList.remove(0);
            }
        }
        //若还有剩下的统一分给第一个机构
        if (smallLmtCasesList.size() > 0 && !smallLmtCasesList.isEmpty()) tempMap.get(orgList.get(0)).addAll(smallLmtCasesList);
        //处理要存入催收催收任务分配数据
        enableDataMap = handleDatas(tempMap, lmtTotal, batchNo);
        return enableDataMap;
    }

    private Map<ColltTaskDistrVO, List<ColltTaskInfoVO>> handleDatas(Map<CaseDistrRatioVO, List<ColltTaskInfoVO>> tempMap, BigDecimal lmtTotal, String batchNo) throws Exception {
        //存处理后的数据
        Map<ColltTaskDistrVO, List<ColltTaskInfoVO>> enableDataMap = new HashMap<>();
        //批次号
        //String colltBatchNo = sequenceService.getSequence("DIVIDE_BATCH",null,null);

        Iterator<CaseDistrRatioVO> iterator = tempMap.keySet().iterator();
        while (iterator.hasNext()) {
            //机构
            CaseDistrRatioVO orgList = iterator.next();
            //机构分配到的案件
            List<ColltTaskInfoVO> rs = tempMap.get(orgList);

            //计算机构分配到的金额
            BigDecimal divLmtTotal = new BigDecimal(0);
            divLmtTotal = rs.stream().map(ColltTaskInfoVO::getOverLmt).reduce(BigDecimal.ZERO, BigDecimal::add);
            //计算金额占比
            BigDecimal proportion = new BigDecimal(0);
            proportion = divLmtTotal.divide(lmtTotal, 4, BigDecimal.ROUND_HALF_UP);

            ColltTaskDistrVO colltTaskDistrVO = new ColltTaskDistrVO();
            colltTaskDistrVO.setColltBatchNo(batchNo);
            colltTaskDistrVO.setOutsOrgCode(orgList.getCooprOrgNo());
            colltTaskDistrVO.setOutsOrgName(orgList.getCooprOrgName());
            colltTaskDistrVO.setOutsHdleType("");
            colltTaskDistrVO.setDistrLmt(divLmtTotal);
            colltTaskDistrVO.setDistrTaskNum(String.valueOf(rs.size()));
            colltTaskDistrVO.setDistrLmtRatio(proportion);
            colltTaskDistrVO.setDistrTasksRatio(orgList.getCaseRatio());
            colltTaskDistrVO.setDistrTime(TimeUtil.getCurrentDateTime());
            colltTaskDistrVO.setCreateTime(TimeUtil.getCurrentDateTime());

            enableDataMap.put(colltTaskDistrVO, rs);
        }
        return enableDataMap;
    }

    private List<CaseDistrRatioVO> checkOrgsInfo(List<CaseDistrRatioVO> orgList) throws Exception {
        List<CaseDistrRatioVO> temp = orgList.stream().filter(a -> a.getCaseRatio() != null).collect(Collectors.toList());
        if (temp.size() == 0)
            throw new Exception("检校机构信息未通过，分案终止。");
        else
            return temp;
    }

    private List<ColltTaskInfoVO> checkCasesInfo(List<ColltTaskInfoVO> caseList) throws Exception {
        List<ColltTaskInfoVO> temp = caseList.stream().filter(a -> a.getOverLmt() != null).collect(Collectors.toList());
        if (temp.size() == 0)
            throw new Exception("检校案件信息未通过，分案终止。");
        else
            return temp;
    }

    private List<ColltTaskInfoVO> queryCasesInfos(ColltTaskDistrVO vo) throws Exception {
        ColltTaskInfoVO colltTaskInfoVO = new ColltTaskInfoVO();
        colltTaskInfoVO.setColltWay(vo.getColltWay());
        colltTaskInfoVO.setIsTaskDistr(BaseConstant.NO_N);
        List<ColltTaskInfoVO> caseList = Optional.ofNullable(colltTaskInfoService.getDistrCaseColltTasks(colltTaskInfoVO)).orElseThrow(() -> new Exception("查询到的案件为空，无法分案！"));
        return caseList;
    }
}
